#include <SDL.h>
#include <assert.h>
#include "scr_state_in_game.h"
#include "scr_state_game_over.h"
#include "scr_game.h"
#include "scr_music.h"
#include "scr_texture.h"
#include "scr_basic_sprite.h"
#include "scr_game_data.h"
#include "scr_marine.h"
#include "scr_camera.h"
#include "scr_math.h"
#include "scr_font.h"
#include "scr_game_state_manager.h"

#define IN_GAME_FONT0_SIZE 24
#define IN_GAME_FONT1_SIZE 24

SCRStateInGame::SCRStateInGame()
	: m_pMapSprite(NULL)
	, m_BulletDelay0(0)
	, m_BulletDelay1(0)
	, m_WeaponType(0)
	, m_Life(1000)
	, m_BulletCount1(0)
	, m_BulletCount2(0)
{
}

SCRStateInGame::~SCRStateInGame()
{
}

void SCRStateInGame::OnInitialize()
{
	m_Font0 = m_pGame->GetResourceManager()->GetFont("fonts/appleberry_with_cyrillic.ttf", IN_GAME_FONT0_SIZE);
	m_Font1 = m_pGame->GetResourceManager()->GetFont("fonts/carbon.ttf", IN_GAME_FONT1_SIZE);
	m_Music = m_pGame->GetResourceManager()->GetMusic("music/music01.ogg");
	m_Music->Play();

	m_Background = m_pGame->GetResourceManager()->GetTexture("images/background.png");
	m_Background->Reload();
	m_pMapSprite = new SCRBasicSprite(m_Background, m_Background->GetData()->w, m_Background->GetData()->h, 0, 0);
	SCRRect Bounds(0, 0, m_Background->GetData()->w, m_Background->GetData()->h);
	m_pGame->GetCamera()->SetBounds(Bounds);
	m_pGame->GetCamera()->SetXY((SCR_MAP_SIZE_X >> 1) - (SCRGame::SCR_SCREEN_WIDTH >> 1),
		(SCR_MAP_SIZE_Y >> 1) - (SCRGame::SCR_SCREEN_HEIGHT >> 1));

	m_pGame->CreateSharedData();
	SCRTexturePtr TextureMarineTop = m_pGame->GetResourceManager()->GetTexture("images/marine_top.png", true);
	SCRTexturePtr TextureMarineBottom = m_pGame->GetResourceManager()->GetTexture("images/marine_bottom.png", true);
	m_pGame->GetSharedData()->CreateMarine(TextureMarineTop, TextureMarineBottom);
	m_pGame->GetSharedData()->GetMarine()->SetXY(SCR_MAP_SIZE_X >> 1, SCR_MAP_SIZE_Y >> 1);

	SCRTexturePtr TextureEnemy = m_pGame->GetResourceManager()->GetTexture("images/enemy.png", true);
	m_pGame->GetSharedData()->CreateEnemy(TextureEnemy);

	SCRTexturePtr TextureBlock = m_pGame->GetResourceManager()->GetTexture("images/block.png", true);
	m_pGame->GetSharedData()->GenerateBlocks(m_Background, TextureBlock);
	m_pGame->GetSharedData()->ClearCheckMap();

	m_pGame->GetSharedData()->InitializeEnemies();
}

void SCRStateInGame::OnUpdate(const int& Delta)
{
	assert(m_pGame->GetSharedData());
	SCRGameData* pSharedData = m_pGame->GetSharedData();

	pSharedData->ClearBuckets();
	pSharedData->ClearCheckMap();
	pSharedData->UpdateEnemies(Delta);
	pSharedData->GetMarine()->Update();

	if (m_BulletDelay0 > 0)
	{
		m_BulletDelay0 -= Delta;
	}

	if (m_BulletDelay1 > 0)
	{
		m_BulletDelay1 -= Delta;
	}

	if (0 == m_WeaponType && SCRMouse::IsPressed(SCRMouseButton::LEFT) && m_BulletDelay0 <= 0)
	{
		m_BulletDelay0 = 33;
		pSharedData->FireProjectile(pSharedData->GetMarine()->GetAngle(), FXIntToFX(16), 1000, 100);
	}

	if (1 == m_WeaponType && SCRMouse::IsPressed(SCRMouseButton::LEFT) && m_BulletDelay1 <= 0)
	{
		m_BulletDelay1 = 99;
		pSharedData->FireProjectile(pSharedData->GetMarine()->GetAngle() - 5000, FXIntToFX(12), 800, 200);
		pSharedData->FireProjectile(pSharedData->GetMarine()->GetAngle() - 2500, FXIntToFX(12), 800, 200);
		pSharedData->FireProjectile(pSharedData->GetMarine()->GetAngle()       , FXIntToFX(12), 800, 200);
		pSharedData->FireProjectile(pSharedData->GetMarine()->GetAngle() + 2500, FXIntToFX(12), 800, 200);
		pSharedData->FireProjectile(pSharedData->GetMarine()->GetAngle() + 5000, FXIntToFX(12), 800, 200);
		m_BulletCount1--;
	}

	if (2 == m_WeaponType && SCRMouse::IsPressed(SCRMouseButton::LEFT))
	{
		pSharedData->FireProjectile(pSharedData->GetMarine()->GetAngle(), FXIntToFX(16), 1000, 70);
		m_BulletCount2--;
	}

	if ((m_WeaponType == 1 && m_BulletCount1 <= 0) || 
		(m_WeaponType == 2 && m_BulletCount2 <= 0))
	{
		m_WeaponType = 0;
	}

	pSharedData->UpdateProjectiles(Delta);
	int PowerUp = pSharedData->UpdatePowerUps(Delta);
	if (PowerUp != 0)
	{
		if (1 == PowerUp)
		{
			m_WeaponType = 1;
			m_BulletCount1 = 600;
		}
		else if (2 == PowerUp)
		{
			m_WeaponType = 2;
			m_BulletCount2 = 800;
		}
	}

	int MarineX = pSharedData->GetMarine()->GetX();
	int MarineY = pSharedData->GetMarine()->GetY();
	if (MarineX >= SCR_MAP_SIZE_X)
	{
		MarineX = SCR_MAP_SIZE_X - 1;
	}
	if (MarineX < 0)
	{
		MarineX = 0;
	}
	if (MarineY >= SCR_MAP_SIZE_Y)
	{
		MarineY = SCR_MAP_SIZE_Y - 1;
	}
	if (MarineY < 0)
	{
		MarineY = 0;
	}

	SCRRect MarineRect(MarineX - 12, MarineY - 12, 24, 24); 
	
	for (std::vector<int>::iterator Iterator = pSharedData->m_Buckets[MarineX >> 8][MarineY >> 8].begin();
		Iterator != pSharedData->m_Buckets[MarineX >> 8][MarineY >> 8].end(); ++Iterator)
	{
		int Index = (*Iterator);
		if (pSharedData->m_EnemiesA[Index].m_Active)
		{
			SCRRect EnemyRect(
				FXFXToInt(pSharedData->m_EnemiesA[Index].m_X) - 12,
				FXFXToInt(pSharedData->m_EnemiesA[Index].m_Y) - 12,
				24, 24);
			if (MarineRect.Intersect(EnemyRect))
			{
				m_Life -= 1;
			}
		}
	}

	if (m_Life <= 0)
	{
		m_pGame->GetStateManager()->SwitchTo<SCRStateGameOver>();
	}
}

void SCRStateInGame::OnRender(const int& Delta)
{
	assert(m_pGame->GetSharedData());
	SCRGameData* pSharedData = m_pGame->GetSharedData();

	m_pMapSprite->Draw(0, 0, 0, 0);
	pSharedData->RenderEnemies(Delta);
	pSharedData->GetMarine()->Draw();
	pSharedData->RenderProjectiles(Delta);
	pSharedData->RenderPowerUps(Delta);

	static char Life[1024];
	sprintf_s(Life, 1024, "Life %i", m_Life);
	m_Font1->Draw(40, 40, Life);

	if (1 == m_WeaponType)
	{
		sprintf_s(Life, 1024, "Shotgun Bullets %i", m_BulletCount1);
		m_Font1->Draw(40, 80, Life);
	}
	else if (2 == m_WeaponType)
	{
		sprintf_s(Life, 1024, "Machinegun Bullets %i", m_BulletCount2);
		m_Font1->Draw(40, 80, Life);
	}
}

void SCRStateInGame::OnTerminate()
{
	if (m_pMapSprite)
	{
		delete m_pMapSprite;
		m_pMapSprite = NULL;
	}

	m_pGame->DestroySharedData();
}

void SCRStateInGame::OnMouseMove(const int& X, const int& Y)
{
}
